﻿using Ndns.ServerHost.Abstractions;
using System;
using System.Collections.Generic;
using Ndns.ServerHost.Abstractions.Services;
using System.Threading.Tasks;

namespace Ndns.ServerHost.Middlewares
{
    class BranchingMiddleware : IMiddleware
    {
        private readonly Func<DnsContext, ValueTask<bool>> _condition;
        private readonly Action<IMiddlewaresBuilder> _builderDelegate;
        private readonly bool _fallThrought;

        private IServiceCollection _services;
        private RequestDelegate _next;

        private MiddlewareNode _head;

        public BranchingMiddleware(Func<DnsContext, ValueTask<bool>> condition, Action<IMiddlewaresBuilder> builderDelegate, bool fallThrought)
        {
            _condition = condition;
            _builderDelegate = builderDelegate;
            _fallThrought = fallThrought;
        }


        public void RegisterServices(IServiceCollection services, RequestDelegate next)
        {
            _services = services;
            _next = next;
        }

        public void Start()
        {
            // 初始化中间件列表
            var middlewares = new List<IMiddleware>();
            var middlewareBuilder = new MiddlewaresBuilder(middlewares);
            _builderDelegate(middlewareBuilder);

            // 构建调用链表
            MiddlewareNode head = middlewares.Count > 0 ? new MiddlewareNode(middlewares[0]) : null;
            MiddlewareNode current = head;
            for (int i = 1; i < middlewares.Count; i++)
            {
                current.Next = new MiddlewareNode(middlewares[i]);
                current = current.Next;
            }

            // 准备Services
            current = head;
            while (current != null)
            {
                if (current.Next != null)
                {
                    current.Middleware.RegisterServices(_services, current.Next.InvokeAsync);
                }
                else
                {
                    if (_fallThrought)
                    {
                        current.Middleware.RegisterServices(_services, _next);
                    }
                    else
                    {
                        current.Middleware.RegisterServices(_services, FallbackMiddleware.StaticInvokeAsync);
                    }
                }
                current = current.Next;
            }
            if (head == null)
            {
                if (_fallThrought)
                {
                    head = new MiddlewareNode(_next);
                }
                else
                {
                    head = new MiddlewareNode(new FallbackMiddleware());
                }
            }

            // 调用Start
            current = head;
            while (current != null)
            {
                current.Middleware.Start();
                current = current.Next;
            }

            _head = head;
        }
        public async Task InvokeAsync(DnsContext context)
        {
            if (!await _condition(context))
            {
                await _next(context);
                return;
            }

            await _head.InvokeAsync(context);
        }

        #region IDisposable Support
        private bool disposedValue = false; // 要检测冗余调用

        protected virtual void Dispose(bool disposing)
        {
            if (!disposedValue)
            {
                if (disposing)
                {
                    // 释放托管状态(托管对象)。
                    _head?.Dispose();
                }

                // 释放未托管的资源(未托管的对象)并在以下内容中替代终结器。
                // 将大型字段设置为 null。
                _head = null;

                disposedValue = true;
            }
        }

        // 仅当以上 Dispose(bool disposing) 拥有用于释放未托管资源的代码时才替代终结器。
        // ~BranchingMiddleware() {
        //   // 请勿更改此代码。将清理代码放入以上 Dispose(bool disposing) 中。
        //   Dispose(false);
        // }

        // 添加此代码以正确实现可处置模式。
        public void Dispose()
        {
            // 请勿更改此代码。将清理代码放入以上 Dispose(bool disposing) 中。
            Dispose(true);
            // 如果在以上内容中替代了终结器，则取消注释以下行。
            // GC.SuppressFinalize(this);
        }
        #endregion
    }
}
